package com.cyb.beta.service.impl;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import com.cyb.beta.service.SafeScheduledExecutorService;
import com.cyb.beta.service.ThreadService;

/**
 * @author chenyongbo
 * @date 2016/4/13.
 */
public class ThreadServiceImpl implements ThreadService{

    private final int processNum = Runtime.getRuntime().availableProcessors();

    private final ThreadPoolExecutor fastExecutor;

    private final ThreadPoolExecutor dbExecutor;

    private final SafeScheduledExecutorService scheduledExecutor;

    public ThreadServiceImpl(){
        this.fastExecutor = new ThreadPoolExecutor(processNum, processNum, 0,
                TimeUnit.SECONDS, new LinkedTransferQueue<Runnable>(),
                new ServiceThreadFactory("fast", Thread.MAX_PRIORITY));

        this.dbExecutor = new ThreadPoolExecutor(processNum, processNum * 2,
                60L, TimeUnit.SECONDS, new LinkedTransferQueue<Runnable>(),
                new ServiceThreadFactory("db"));

        this.scheduledExecutor = new SafeScheduledExecutorService(
                new ScheduledThreadPoolExecutor(processNum * 2,
                        new ServiceThreadFactory("update")));
    }

    @Override
    public ExecutorService getFastExecutor(){
        return fastExecutor;
    }

    @Override
    public ExecutorService getDbExecutor(){
        return dbExecutor;
    }

    @Override
    public SafeScheduledExecutorService getScheduledExecutorService(){
        return scheduledExecutor;
    }

    @Override
    public void close(){
        fastExecutor.shutdown();
        dbExecutor.shutdown();
        scheduledExecutor.getService().shutdown();
    }

    static class ServiceThreadFactory implements ThreadFactory{
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
        private final int priority;

        ServiceThreadFactory(String poolNamePrefix){
            this(poolNamePrefix, Thread.NORM_PRIORITY);
        }

        ServiceThreadFactory(String poolNamePrefix, int priority){
            poolNamePrefix = (poolNamePrefix != null) ? poolNamePrefix
                    : "pool-" + poolNumber.getAndIncrement();
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread()
                    .getThreadGroup();
            namePrefix = poolNamePrefix + "-work-";
            this.priority = priority;
        }

        @Override
        public Thread newThread(Runnable r){
            Thread t = new Thread(group, r, namePrefix
                    + threadNumber.getAndIncrement(), 0);
            if (t.isDaemon()){
                t.setDaemon(false);
            }
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(priority);
            return t;
        }
    }
}
